import { Injectable } from '@angular/core';
import { Storage } from '@ionic/storage';
import { TranslateService } from '@ngx-translate/core';
import { File } from '@ionic-native/file';

import { GlobalData } from '../providers/GlobalData';
import { HelperService } from './services.helper';
import { OfflineService } from './services.offline';

declare var epson: any;
declare var domtoimage: any;

@Injectable()
export class PrinterService {

  settings: any;
  departmentId: any;
  epsonPrinters: any = {};

  constructor(
    private storage: Storage,
    private helperService: HelperService,
    private global: GlobalData,
    private offline: OfflineService,
    private translate: TranslateService,
    private file: File) {

    this.getEpsonPrinters();

    // // 2017-6-20 - TK: added to handle multiple printer
    // this.epsonPrinters = {
    //   // pre-configured printer pool for internal testing. department id as key
    //   '0': { ipAddr: '192.168.1.237', port: 8008, deviceId: 'local_printer', deviceObj: null, printerObj: null, builder: null, connected: false, printing: false },
    //   '1': { ipAddr: '192.168.1.239', port: 8008, deviceId: 'local_239', deviceObj: null, printerObj: null, builder: null, connected: false, printing: false },
    //   //'default':  { ipAddr: '192.168.1.239', port: 8008, deviceId: 'local_printer', deviceObj: null, printerObj: null, connected: false, printing: false },
    // };

  }

  getEpsonPrinters() {
    this.storage.get('settings').then((setting) => {
      if (setting != null) {
        this.settings = setting;
        if (setting.departments) {
          this.epsonPrinters[setting.departments[0].id.toString()] = {};
          this.epsonPrinters[setting.departments[0].id.toString()] = {
            ipAddr: setting.epson_ip_address,
            port: setting.epson_port,
            deviceId: setting.epson_device_id,
            deviceObj: null,
            printerObj: null,
            builder: null,
            connected: false,
            printing: false
          };
          console.log(setting.departments['0'].id, setting.epson_ip_address, setting.epson_port, setting.epson_device_id, this.epsonPrinters);
        }
      }
    });
  }

  /**************************************************
  // open cashier drawer by department id
  **************************************************/
  esponOpenDrawerByDepartmentId(departmentId) {
    this.epsonPrinters[departmentId]['printerObj'].addPulse(this.epsonPrinters[departmentId]['printerObj'].DRAWER_1, this.epsonPrinters[departmentId]['printerObj'].PULSE_100);
    this.epsonPrinters[departmentId]['printerObj'].send();
  }

  /**************************************************
  // prepare and print canvas immediately
  **************************************************/
  epsonPrepareAndPrintCanvas(html) {
    return new Promise((resolve, reject) => {
      let t = performance.now();
      let div = document.createElement('div');
      div.className = 'printer-content';
      div.innerHTML = html;
      let departmentId = (<Element>div.childNodes[0]).getAttribute('data-department-id');
      document.getElementById('global-print-page').appendChild(div);
      console.log('start prepare canvas in ' + (performance.now() - t) + ' ms');
      domtoimage.draw(div, {}).then((canvas) => {
        console.log('completed prepare canvas in ' + (performance.now() - t) + ' ms');
        document.getElementById('printer-canvas').appendChild(canvas);
        div.parentNode.removeChild(div);

        // canvas print
        console.log('start printing in ' + (performance.now() - t) + ' ms');
        let address = 'http://' + this.epsonPrinters[departmentId]['ipAddr'] + '/cgi-bin/epos/service.cgi?devid=' + this.epsonPrinters[departmentId]['deviceId'] + '&timeout=60000';
        this.epsonPrinters[departmentId]['printerObj'] = new epson.CanvasPrint(address);
        this.epsonPrinters[departmentId]['printerObj'].onreceive = (res) => {
          console.log('received printing result in ' + (performance.now() - t) + ' ms');
          canvas.parentNode.removeChild(canvas);
          this.epsonPrinters[departmentId]['printerObj'] = null;
          resolve();
        };
        this.epsonPrinters[departmentId]['printerObj'].halftone = this.epsonPrinters[departmentId]['printerObj'].HALFTONE_DITHER;
        this.epsonPrinters[departmentId]['printerObj'].cut = true;
        this.epsonPrinters[departmentId]['printerObj'].mode = this.epsonPrinters[departmentId]['printerObj'].MODE_MONO;
        this.epsonPrinters[departmentId]['printerObj'].print(canvas);
      }, (err) => {
        reject(err);
      });
    });
  }

  /**************************************************
  // print multiple canvas immediately
  **************************************************/
  epsonPrintMultipleCanvas(css, htmls) {
    document.getElementById('printer-css').innerHTML = css;
    document.getElementById('printer-canvas').innerHTML = '';
    for (let i = 0; i < htmls.length; i++) {
      this.epsonPrepareAndPrintCanvas(htmls[i]).then(() => {
        console.log('printing completed ' + i);
      }, (err) => {
        console.log('printing error' + err);
      });
    }
  }

  /**************************************************
  // append canvas for future printing
  **************************************************/
  epsonAppendCanvas(html) {
    return new Promise((resolve, reject) => {
      let div = document.createElement('div');
      div.className = 'printer-content';
      div.innerHTML = html;
      let departmentId = (<Element>div.childNodes[0]).getAttribute('data-department-id');
      document.getElementById('global-print-page').appendChild(div);
      domtoimage.draw(div, {}).then((canvas) => {
        canvas.setAttribute('data-department-id', departmentId);
        document.getElementById('printer-canvas').appendChild(canvas);
        div.parentNode.removeChild(div);
        resolve();
      }, (err) => {
        reject(err);
      });
    });
  }

  /**************************************************
  // prepare multiple canvas for future printing
  **************************************************/
  epsonPrepareMultipleCanvas(css, htmls) {
    this.global.setScope('epsonCanvasReady', false);
    document.getElementById('printer-css').innerHTML = css;
    document.getElementById('printer-canvas').innerHTML = '';
    this.global.setScope('epsonPageCount', htmls.length);
    this.global.setScope('epsonPageReadyCount', 0);
    for (let i = 0; i < htmls.length; i++) {
      this.epsonAppendCanvas(htmls[i]).then((res) => {
        this.global.setScope('epsonPageReadyCount', this.global.getScope('epsonPageReadyCount') + 1);
        console.log('page count ' + this.global.getScope('epsonPageReadyCount'));
        if (this.global.getScope('epsonPageReadyCount') == this.global.getScope('epsonPageCount')) {
          console.log('epson all canvas ready');
          this.global.setScope('epsonCanvasReady', true);
        }
      }, (err) => {
        // handle html2canvas error
      });
    }
  }

  /**************************************************
  // print prepared canvas
  **************************************************/
  epsonPrintPreparedCanvas() {
    if (!this.global.getScope('epsonCanvasReady')) {
      setTimeout(() => {
        console.log('recall printing');
        this.epsonPrintPreparedCanvas();
      }, 100);
      return;
    }
    for (let i = 0; i < document.getElementById('printer-canvas').getElementsByTagName('canvas').length; i++) {
      let canvas = document.getElementById('printer-canvas').getElementsByTagName('canvas')[i];
      if (canvas.getContext) {
        let departmentId = canvas.getAttribute('data-department-id').toString();
        let address = 'http://' + this.epsonPrinters[departmentId].ipAddr + '/cgi-bin/epos/service.cgi?devid=' + this.epsonPrinters[departmentId].deviceId + '&timeout=60000';

        // canvas print
        /*this.epsonPrinters[departmentId].printerObj = new epson.CanvasPrint(address);
        this.epsonPrinters[departmentId].printerObj.onreceive = (res) => {
          console.log('printing completed');
          canvas.parentNode.removeChild(canvas);
        };
        this.epsonPrinters[departmentId].printerObj.halftone = this.epsonPrinters[departmentId].printerObj.HALFTONE_DITHER;
        this.epsonPrinters[departmentId].printerObj.cut = true;
        this.epsonPrinters[departmentId].printerObj.mode = this.epsonPrinters[departmentId].printerObj.MODE_MONO;
        this.epsonPrinters[departmentId].printerObj.print(canvas);*/

        // epos print
        if (this.epsonPrinters[departmentId].printerObj == null) {
          this.epsonPrinters[departmentId].printerObj = new epson.ePOSPrint(address);
          this.epsonPrinters[departmentId].printerObj.onreceive = (res) => {
            console.log('printing completed');
            //canvas.parentNode.removeChild(canvas);
            this.epsonPrinters[departmentId].printerObj.close();
            this.epsonPrinters[departmentId].printerObj = null;
          };
          this.epsonPrinters[departmentId].builder = new epson.ePOSBuilder();
        }
        //this.epsonPrinters[departmentId].builder.brightness = 0.3;
        //this.epsonPrinters[departmentId].builder.halftone = this.epsonPrinters[departmentId].builder.HALFTONE_DITHER;
        this.epsonPrinters[departmentId].builder.addImage(canvas.getContext('2d'), 0, 0, canvas.width, canvas.height, this.epsonPrinters[departmentId].builder.COLOR_1, this.epsonPrinters[departmentId].builder.MODE_MONO);
        this.epsonPrinters[departmentId].builder.addCut(this.epsonPrinters[departmentId].builder.CUT_FEED);
      }
    }

    for (let key in this.epsonPrinters) {
      if (this.epsonPrinters[key].printerObj != null) {
        this.epsonPrinters[key].printerObj.send(this.epsonPrinters[key].builder.toString());
      }
    }
  }

  printDirect(receipt, type) {
    this.getEpsonPrinters();
    console.log(this.epsonPrinters, receipt);

    var shopAddress: string = '';
    if (this.global.curPrintLang == 'ZH_HK' && this.global.warehouse.warehouse_ZH_HK) {
      shopAddress = this.global.warehouse.warehouse_ZH_HK;
    } else if (this.global.curPrintLang == 'ZH_CN' && this.global.warehouse.warehouse_ZH_CN) {
      shopAddress = this.global.warehouse.warehouse_ZH_CN;
    } else if (this.global.curPrintLang == 'EN_US' && this.global.warehouse.warehouse_EN_US) {
      shopAddress = this.global.warehouse.warehouse_EN_US;
    } else {
      shopAddress = this.global.warehouse.warehouse_EN_US;
    }

    var memberClass: string = '';
    if (receipt.customer_info.user_id == '') {
      memberClass = this.translate.instant('Visitor');
    } else {
      memberClass = receipt.customer_info.vip_level;
    }

    var departmentDic: { [department_id: number]: any; } = {};
    for (let department of receipt.department_list) {
      for (let product of receipt.products) {
        if (department == product.department_id) {
          if (!departmentDic[department]) {
            departmentDic[department] = [];
            departmentDic[department].push(product);
          } else {
            departmentDic[department].push(product);
          }
        }
      }
    }

    var itemDic: { [item_id: number]: any; } = {};
    for (let product of receipt.products) {
      if (!itemDic[product.item_id]) {
        itemDic[product.item_id] = [];
        itemDic[product.item_id].push(product);
      } else {
        itemDic[product.item_id].push(product);
      }
    }

    var productList: any = [];
    if (this.global.isPrintByDepartment) {
      for (var key in departmentDic) {
        productList.push(departmentDic[key]);
      }
    } else {
      for (var key in itemDic) {
        productList.push(itemDic[key]);
      }
    }

    console.log(shopAddress, memberClass, productList, 1000);

    this.file.readAsDataURL(this.helperService.getRootPath(), this.global.shopIconFile).then((logo) => {
      let data = {
        size: '80mm',
        pages: []
      };
      for (let plist of productList) {
        if ((type == 'order' && plist[0].served != 0) ||
          (type == 'order_add' && plist[0].served != 0)) {
          continue;
        }
        if ((type == 'order' && plist[0].served == 0) ||
          (type == 'order_add' && plist[0].served == 0) ||
          (type == 'order_all' && plist[0].served == 0)) {
          plist[0].served = 2;
        }

        var departmentName: string = '';
        if (this.global.curPrintLang == 'ZH_HK') {
          departmentName = plist[0].department_name_ZH_HK;
        } else if (this.global.curPrintLang == 'ZH_CN') {
          departmentName = plist[0].department_name_ZH_CN;
        } else if (this.global.curPrintLang == 'EN_US') {
          departmentName = plist[0].department_name_EN_US;
        }

        var productItem: any = [];
        for (let p of plist) {
          console.log(p, 1001);

          var invoice_option = '';
          var print_type = '';
          if (type == 'order_all') {
            print_type = 'order';
            invoice_option += this.translate.instant('REPRINT');
          }
          if (type == 'order_add') {
            print_type = 'order';
            invoice_option += this.translate.instant('ADD_ORDER');
          }

          var options = '<br/>';

          for (var i = p.options.length - 1; i >= 0; i--) {
            if (p.options[i].options[0] != '不需要') {
              if (i > 0) {
                options = options + ' ';
              }
              options = options + p.options[i].options[0];
            }
          }

          for (var i = p.addons.length - 1; i >= 0; i--) {
            if (p.addons[i].qty > 0) {
              if (i > 0) {
                options = options + ' ';
              }
              if (this.global.curPrintLang == 'EN_US') {
                options = options + p.addons[i].name_EN_US + '*' + p.addons[i].qty;
              } else if (this.global.curPrintLang == 'ZH_CN') {
                options = options + p.addons[i].name_ZH_CN + '*' + p.addons[i].qty;
              } else {
                options = options + p.addons[i].name_ZH_HK + '*' + p.addons[i].qty;
              }
            }
          }
          if (options.length == 5) {
            options = '';
          }

          var dis: string = '';
          if (Number(p.o_price) == Number(p.unit_price) || Number(p.unit_price) == 0) {
            dis = '-';
          } else {
            dis = (Number(p.o_price) - Number(p.unit_price)) / Number(p.o_price) * 100 + '';
            dis = Number(dis).toFixed(1) + '%';
          }
          productItem.push({
            PRODUCT_NAME: p.qty == 0 ? p.name + '(' + this.translate.instant('CANCELLED') + ')' + options : p.name + options,
            QTY: p.qty,
            DISCOUNT: dis,
            SUB_TOTAL: '$' + p.sub_total.toFixed(1),
            SHOW_PRICE: print_type == 'order' ? 'none' : ''  // 'block', 'none'. show/hide price
          });
        }

        console.log(productItem);

        var charges = [];
        var baseTotal = receipt.item_total;

        for (var i = 0; i < receipt.invoice_charges.length; i++) {
          var charge = receipt.invoice_charges[i];
          if (charge.value_type == 'percent') {
            if (charge.sign == '+') {
              //service charge
              var totalFlag = baseTotal;
              var charge_value = charge.value + '%';
              baseTotal *= 1 + Number(charge.value) / 100;
              var baseCharge = baseTotal - totalFlag;
              if (this.global.curPrintLang == 'EN_US') {
                if (Number(charge.value) != 0)
                  charges.push({
                    CHARGE_NAME: charge.title_EN_US,
                    CHARGE_VALUE: charge_value,
                    CHARGE_VALUE_TYPE: charge.value_type,
                    CHARGE_AMOUNT: '$' + Number(baseCharge).toFixed(1),
                    CHARGE_SIGN: charge.sign
                  });

              } else if (this.global.curPrintLang == 'ZH_ZN') {
                if (Number(charge.value) != 0)
                  charges.push({
                    CHARGE_NAME: charge.ZH_ZN,
                    CHARGE_VALUE: charge_value,
                    CHARGE_VALUE_TYPE: charge.value_type,
                    CHARGE_AMOUNT: '$' + Number(baseCharge).toFixed(1),
                    CHARGE_SIGN: charge.sign
                  });

              } else {
                if (Number(charge.value) != 0)
                  charges.push({
                    CHARGE_NAME: charge.title_ZH_HK,
                    CHARGE_VALUE: charge_value,
                    CHARGE_VALUE_TYPE: charge.value_type,
                    CHARGE_AMOUNT: '$' + Number(baseCharge).toFixed(1),
                    CHARGE_SIGN: charge.sign
                  });

              }
            } else if (charge.sign == '-') {
              //discount
              var totalFlag = baseTotal;
              var charge_value = '(' + charge.value + '%)';
              baseTotal *= 1 - Number(charge.value) / 100;
              var baseDiscount = totalFlag - baseTotal;
              if (this.global.curPrintLang == 'EN_US') {
                if (Number(charge.value) != 0)
                  charges.push({
                    CHARGE_NAME: charge.title_EN_US,
                    CHARGE_VALUE: charge_value,
                    CHARGE_VALUE_TYPE: charge.value_type,
                    CHARGE_AMOUNT: '($' + Number(baseDiscount).toFixed(1) + ')',
                    CHARGE_SIGN: charge.sign
                  });

              } else if (this.global.curPrintLang == 'ZH_ZN') {
                if (Number(charge.value) != 0)
                  charges.push({
                    CHARGE_NAME: charge.ZH_ZN,
                    CHARGE_VALUE: charge_value,
                    CHARGE_VALUE_TYPE: charge.value_type,
                    CHARGE_AMOUNT: '($' + Number(baseDiscount).toFixed(1) + ')',
                    CHARGE_SIGN: charge.sign
                  });

              } else {
                if (Number(charge.value) != 0)
                  charges.push({
                    CHARGE_NAME: charge.title_ZH_HK,
                    CHARGE_VALUE: charge_value,
                    CHARGE_VALUE_TYPE: charge.value_type,
                    CHARGE_AMOUNT: '($' + Number(baseDiscount).toFixed(1) + ')',
                    CHARGE_SIGN: charge.sign
                  });
              }
            }
          }
        }

        for (var i = 0; i < receipt.invoice_charges.length; i++) {
          var charge = receipt.invoice_charges[i];
          if (charge.value_type != 'percent') {

            if (charge.sign == '+') {
              //service charge
              var totalFlag = baseTotal;
              var charge_value = '$' + charge.value;
              baseTotal += Number(charge.value);
              var baseCharge = baseTotal - totalFlag;
              if (this.global.curPrintLang == 'EN_US') {
                if (Number(charge.value) != 0)
                  charges.push({
                    CHARGE_NAME: charge.title_EN_US,
                    CHARGE_VALUE: '',
                    CHARGE_VALUE_TYPE: charge.value_type,
                    CHARGE_AMOUNT: '$' + Number(baseCharge).toFixed(1),
                    CHARGE_SIGN: charge.sign
                  });

              } else if (this.global.curPrintLang == 'ZH_ZN') {
                if (Number(charge.value) != 0)
                  charges.push({
                    CHARGE_NAME: charge.ZH_ZN,
                    CHARGE_VALUE: '',
                    CHARGE_VALUE_TYPE: charge.value_type,
                    CHARGE_AMOUNT: '$' + Number(baseCharge).toFixed(1),
                    CHARGE_SIGN: charge.sign
                  });

              } else {
                if (Number(charge.value) != 0)
                  charges.push({
                    CHARGE_NAME: charge.title_ZH_HK,
                    CHARGE_VALUE: '',
                    CHARGE_VALUE_TYPE: charge.value_type,
                    CHARGE_AMOUNT: '$' + Number(baseCharge).toFixed(1),
                    CHARGE_SIGN: charge.sign
                  });
              }

            } else if (charge.sign == '-') {
              //discount
              var totalFlag = baseTotal;
              var charge_value = '($' + charge.value + ')';
              baseTotal -= Number(charge.value);
              var baseDiscount = totalFlag - baseTotal;
              if (this.global.curPrintLang == 'EN_US') {
                if (Number(charge.value) != 0)
                  charges.push({
                    CHARGE_NAME: charge.title_EN_US,
                    CHARGE_VALUE: '',
                    CHARGE_VALUE_TYPE: charge.value_type,
                    CHARGE_AMOUNT: '($' + Number(baseDiscount).toFixed(1) + ')',
                    CHARGE_SIGN: charge.sign
                  });

              } else if (this.global.curPrintLang == 'ZH_ZN') {
                if (Number(charge.value) != 0)
                  charges.push({
                    CHARGE_NAME: charge.ZH_ZN,
                    CHARGE_VALUE: '',
                    CHARGE_VALUE_TYPE: charge.value_type,
                    CHARGE_AMOUNT: '($' + Number(baseDiscount).toFixed(1) + ')',
                    CHARGE_SIGN: charge.sign
                  });

              } else {
                if (Number(charge.value) != 0)
                  charges.push({
                    CHARGE_NAME: charge.title_ZH_HK,
                    CHARGE_VALUE: '',
                    CHARGE_VALUE_TYPE: charge.value_type,
                    CHARGE_AMOUNT: '($' + Number(baseDiscount).toFixed(1) + ')',
                    CHARGE_SIGN: charge.sign
                  });
              }
            }
          }
        }

        console.log(charges);

        data.pages.push({
          COMPANY_LOGO: logo,  // company logo in base64 data
          SHOW_COMPANY_LOGO: print_type == 'order' ? 'none' : '',  // '', 'none'. show/hide company logo
          SHOP_TEL: this.global.warehouse.warehouse_tel,  // shop tel no
          SHOP_ADDRESS: shopAddress,  // shop address
          SHOW_SHOP_INFO: print_type == 'order' ? 'none' : '',  // '', 'none'. show/hide shop info
          INVOICE_TITLE: receipt.payed_amount > 0 ? this.translate.instant('PRINT_RECEIPT') : this.translate.instant('PRINT_INVOICE'),  // '收據', '發票'
          SHOW_INVOICE_TITLE: print_type == 'order' ? 'none' : '',  // '', 'none'. show/hide invoice title
          TICKET_TYPE: receipt.table_num == '0' ? this.translate.instant('TICKET_NO') : this.translate.instant('TABLE'),  // '檯號'/ '单号'
          TICKET_NO: receipt.table_num == '0' ? receipt.ticket_num : receipt.table_num,  // ticket no. or table no.
          INVOICE_TYPE: receipt.table_num == '0' ? this.translate.instant('TAKE_AWAY') : this.translate.instant('DINE_IN'),  // '堂食'/ '外賣'
          MBER_CLASS: memberClass, // member class
          SHOW_MEMBER_CLASS: print_type == 'order' ? 'none' : '',  // '', 'none'. show/hide member class
          INVOICE_DATE: receipt.invoice_date,  // invoice date
          INVOICE_NO: receipt.ticket_num,  // invoice no.
          SHOW_INVOICE_NO: receipt.table_num == '0' ? 'none' : '',  // '', 'none'. show/hide invoice no
          SALESMAN: receipt.sales,  // salesman
          SHOW_SALESMAN: print_type == 'order' ? 'none' : '',  // '', 'none'. show/hide salesman
          DEPARTMENT_ID: plist[0].department_id.toString(),  //
          DEPARTMENT_NAME: invoice_option == '' ? departmentName : departmentName + '-' + invoice_option,  // department name 
          SHOW_DEPARTMENT_NAME: print_type == 'order' ? '' : 'none',  // '', 'none'. show/hide department name
          SHOW_PRICE: print_type == 'order' ? 'none' : '',  // '', 'none'. show/hide price
          PRODUCT_ITEM: productItem,
          CHARGE_ITEM: charges,
          ITEM_TOTAL: '$' + Number(receipt.item_total).toFixed(1),
          GRAND_TOTAL: '$' + receipt.grand_total.toFixed(1),
          CASH_RECEIVED: '$' + (Number(receipt.payed_amount) > 0 ? Number(receipt.payed_amount).toFixed(1) : '0.0'),
          CHANGES: '$' + ((Number(receipt.payed_amount) - receipt.temp_grand_total) > 0 ? (Number(receipt.payed_amount) - receipt.temp_grand_total).toFixed(1) : '0.0'),
          SHOW_PAYMENT_DETAIL: print_type == 'receipt' ? '' : 'none',
          SHOW_RECEIVE_DETAIL: print_type == 'receipt' ? '' : 'none',
          DEVICE_NO: 'B028172',
          OCTOPUS_NO: receipt.coupon_no,
          AMOUNT_DEDUCTED: '$-130.0',
          REMAINING_VALUE: '$999.0',
          DEDUCT_DATE: receipt.octopus_info != '' && receipt.octopus_info != null ? '' : 'none',
          SHOW_OCTOPUS: receipt.octopus_info != '' && receipt.octopus_info != null ? '' : 'none',
          SHOW_FOOTER: print_type == 'order' ? 'none' : '',
        });
      }
      console.log(data);
      this.translate.use(this.global.curPrintLang);
      this.offline.getInvoiceHtml(data).then(res => {
        this.translate.use(this.global.curLang);
        this.epsonPrintMultipleCanvas(res.css, res.htmls);
      }, err => {
        alert(err);
      });
    });
  }

}
